
#pragma once

#include "..\\ExternalTools\\ExternalTools.h"

#include "..\\Loirey\\loirey_GLOBAL.h"
#include "..\\Loirey\\loirey_MyMath.h"
#include "..\\Loirey\\loirey_BasicStructure.h"

#include "cvf_ImageFilter.h"
#include "cvf_Gradient.h"
#include "cvf_ImageTransform.h"

using namespace loirey;

class CImageFilter_Gray : public CImageFilter
{
public:
	CImageFilter* myClone() const;
	int GetResponseDimension();
protected:
	virtual void _ComputeResponse(int W, int H, double** ppInputResponse, double* pResponse);
};

class CImageFilter_Lab : public CImageFilter
{
public:
	CImageFilter* myClone() const;
	int GetResponseDimension();
protected:
	virtual void _ComputeResponse(int W, int H, double** ppInputResponse, double* pResponse);
};

class CImageFilter_Func_Sqrt : public CImageFilter
{
public:
	CImageFilter* myClone() const;
	int GetResponseDimension();
protected:
	virtual void _ComputeResponse(int W, int H, double** ppInputResponse, double* pResponse);
};

class CImageFilter_Kernel2D : public CImageFilter
{
public:
	CKernel2D<double> Ker;

public:
	virtual size_t GetMemoryUsage() const;
public:
	CImageFilter* myClone() const;
	int GetResponseDimension();
protected:
	virtual void _ComputeResponse(int W, int H, double** ppInputResponse, double* pResponse);
};

class CImageFilter_Gaussian : public CImageFilter
{
public:
	CKernel2D<double> Ker;

public:
	CImageFilter_Gaussian(double Sigma) : CImageFilter()
	{
		CKernel2D<double>::GenerateGaussian(Ker, Sigma);
	}
	CImageFilter_Gaussian(double SigmaX, double SigmaY) : CImageFilter()
	{
		CKernel2D<double>::GenerateGaussian(Ker, SigmaX, SigmaY);
	}
public:
	virtual size_t GetMemoryUsage() const;
public:
	CImageFilter* myClone() const;
	int GetResponseDimension();
protected:
	virtual void _ComputeResponse(int W, int H, double** ppInputResponse, double* pResponse);
};

class CImageFilter_LoG : public CImageFilter
{
public:
	CKernel2D<double> Ker;

public:
	CImageFilter_LoG(double Sigma) : CImageFilter()
	{
		CKernel2D<double>::GenerateLaplacianOfGaussian(Ker, Sigma);
	}
public:
	virtual size_t GetMemoryUsage() const;
public:
	CImageFilter* myClone() const;
	int GetResponseDimension();
protected:
	virtual void _ComputeResponse(int W, int H, double** ppInputResponse, double* pResponse);
};

class CImageFilter_1DoG : public CImageFilter
{
public:
	CKernel2D<double> Ker;

public:
	CImageFilter_1DoG(bool fIsTypeX, double Sigma) : CImageFilter()
	{
		if (fIsTypeX)
			CKernel2D<double>::GenerateGaussian1stDerivativeX(Ker, 1.0 * Sigma, 3.0 * Sigma);
		else
			CKernel2D<double>::GenerateGaussian1stDerivativeY(Ker, 3.0 * Sigma, 1.0 * Sigma);
	}
	CImageFilter_1DoG(bool fIsTypeX, double SigmaX, double SigmaY) : CImageFilter()
	{
		if (fIsTypeX)
			CKernel2D<double>::GenerateGaussian1stDerivativeX(Ker, SigmaX, SigmaY);
		else
			CKernel2D<double>::GenerateGaussian1stDerivativeY(Ker, SigmaX, SigmaY);
	}
public:
	virtual size_t GetMemoryUsage() const;
public:
	CImageFilter* myClone() const;
	int GetResponseDimension();
protected:
	virtual void _ComputeResponse(int W, int H, double** ppInputResponse, double* pResponse);
};

class CImageFilter_DooG : public CImageFilter
{
public:
	CImg<double> Ker;
	double Sigma, Orientation, Aspect;

public:
	CImageFilter_DooG(double Sigma, double Orientation, double Aspect) : CImageFilter()
	{
		this->Sigma = Sigma;
		this->Orientation = Orientation;
		this->Aspect = Aspect;
		BuildKer(Ker, Sigma, Orientation, Aspect);
	}
public:
	virtual size_t GetMemoryUsage() const;
public:
	static void BuildKer(CImg<double>& imgDstKer, double Sigma, double Orientation, double Aspect);
public:
	CImageFilter* myClone() const;
	int GetResponseDimension();
protected:
	virtual void _ComputeResponse(int W, int H, double** ppInputResponse, double* pResponse);
};

class CImageFilter_DoG : public CImageFilter
{
public:
	CImg<double> Ker;

public:
	static void BuildKer(CImg<double>& imgDstKer, double Sigma);
public:
	CImageFilter_DoG(double Sigma) : CImageFilter()
	{
		BuildKer(Ker, Sigma);
	}
public:
	virtual size_t GetMemoryUsage() const;
public:
	CImageFilter* myClone() const;
	int GetResponseDimension();
protected:
	virtual void _ComputeResponse(int W, int H, double** ppInputResponse, double* pResponse);
};

class CImageFilter_Gradient : public CImageFilter
{
public:
	double GaussianSigma;
	bool fUseSignedOrientation;

public:
	CImageFilter_Gradient(double GaussianSigma, bool fUseSignedOrientation);
public:
	virtual size_t GetMemoryUsage() const;
public:
	CImageFilter* myClone() const;
	int GetResponseDimension();
protected:
	virtual void _ComputeResponse(int W, int H, double** ppInputResponse, double* pResponse);
};

class CImageFilter_2D_Histogram : public CImageFilter
{
public:
	static const int MODE_BOUNDING = 0;
	static const int MODE_NEAREST = 1;
public:
	int ResponseInputIndex_Weight;
	int ResponseInputIndex_Orientation;
	int BinAmount;
	double ValueBoundA;
	double ValueBoundB;
	int BinSelectMode;
	bool fAreBinWrapped;
	CHistogramConfig HistogramConfig;

public:
	CImageFilter_2D_Histogram(
		int ResponseInputIndex_Weight, int ResponseInputIndex_Orientation,
		int BinAmount, double ValueBoundA, double ValueBoundB,
		int BinSelectMode, bool fAreBinWrapped);
public:
	virtual size_t GetMemoryUsage() const;
public:
	CImageFilter* myClone() const;
	int GetResponseDimension();
protected:
	virtual void _ComputeResponse(int W, int H, double** ppInputResponse, double* pResponse);
};

class CImageFilter_LinearCombination : public CImageFilter
{
public:
	CSimpleTypeArray<double> InputWeightList;
	CSimpleTypeArray<int> InputOffset_X_List;
	CSimpleTypeArray<int> InputOffset_Y_List;

public:
	CImageFilter_LinearCombination();
public:
	virtual void Clear_IO_Relationship();
	virtual void PushBackInputResponse(
		CImageFilter* pFilter, int ResponseIndex,
		double Weight = 1.0, int Offset_X = 0, int Offset_Y = 0);
public:
	virtual size_t GetMemoryUsage() const;
public:
	CImageFilter* myClone() const;
	int GetResponseDimension();
protected:
	virtual void _ComputeResponse(int W, int H, double** ppInputResponse, double* pResponse);
};

class CImageFilter_CannyEdge : public CImageFilter
{
public:
	double Sigma, tLow, tHigh, OriMin, OriMax;
	bool fUseSignedOrientation;

public:
	CImageFilter_CannyEdge(double Sigma, double tLow, double tHigh, double PrimaryOrientation, double OrientationWidth, bool fUseSignedOrientation);
public:
	virtual size_t GetMemoryUsage() const;
public:
	CImageFilter* myClone() const;
	int GetResponseDimension();
protected:
	virtual void _ComputeResponse(int W, int H, double** ppInputResponse, double* pResponse);
};

class CEdgeForest
{
public:
	class CNodeOfEdgeTree
	{
	public:
		int x,y;
		double OriginalDirection;
		double SmoothedDirection;
		CNodeOfEdgeTree* pParent;
		int Label;
		int maxEdgeLength;
		int maxUpLength;
		int maxDownLength;
		CNodeOfEdgeTree* pDownLength1st;
		CNodeOfEdgeTree* pDownLength2nd;
	};

private:
	double _DirectionThreshold;
public:
	static int NMOV;
	static const int MAX_NMOV = 8;
	static const int XMOV[MAX_NMOV];
	static const int YMOV[MAX_NMOV];
protected:
	bool* _matMag;
	double* _matOri;
public:
	int W,H,WH;
	CNodeOfEdgeTree* rgNode;
	int OffsetMov[MAX_NMOV];
	int TreeCount;

public:
	void myRelease();
	CEdgeForest();
	virtual ~CEdgeForest();
public:
	template<typename TMag, typename TOri>
	void myInit(int W, int H, const TMag* matMag, const TOri* matOri, const TMag& Threshold, bool fSign = true)
	{
		int i;
		CNodeOfEdgeTree* pCurrentNode;

		myRelease();

		this->W = W; this->H = H; WH = W * H;
		rgNode = new CNodeOfEdgeTree[WH];
		for ( i = 0; i < NMOV; ++i )
			OffsetMov[i] = XMOV[i] + YMOV[i] * W;

		_matMag = new bool[WH];
		_matOri = new double[WH];

		for ( i = 0; i < WH; ++i )
		{
			_matMag[i] = (((double)(matMag[i] - Threshold) < EPS) ^ fSign);
			_matOri[i] = (double)matOri[i];
			pCurrentNode = rgNode + i;
			pCurrentNode->x = i%W;
			pCurrentNode->y = i/W;
		}
	}
public:
	void GenerateForest(double DirectionThreshold);
	void TraceFirstRound(CNodeOfEdgeTree* pRoot);
	void TraceSecondRound(CNodeOfEdgeTree* pRoot);
};

class CImageFilter_EdgeForest : public CImageFilter
{
public:
	double MagThreshold;
	bool fTrueMagSign;
	int LengthThreshold;
	double DirectionThreshold;

public:
	CImageFilter_EdgeForest(double MagThreshold, bool fTrueMagSign, int LengthThreshold, double DirectionThreshold);
public:
	virtual size_t GetMemoryUsage() const;
public:
	CImageFilter* myClone() const;
	int GetResponseDimension();
protected:
	virtual void _ComputeResponse(int W, int H, double** ppInputResponse, double* pResponse);
};

////////////////////////////////////////////////////////////////

